home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / OUTAOUT.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  13KB  |  468 lines

  1. /* outaout.c    output routines for the Netwide Assembler to produce
  2.  *        Linux a.out object files
  3.  *
  4.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  5.  * Julian Hall. All rights reserved. The software is
  6.  * redistributable under the licence given in the file "Licence"
  7.  * distributed in the NASM archive.
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include "nasm.h"
  16. #include "nasmlib.h"
  17. #include "outform.h"
  18.  
  19. #ifdef OF_AOUT
  20.  
  21. struct Reloc {
  22.     struct Reloc *next;
  23.     long address;               /* relative to _start_ of section */
  24.     long symbol;               /* symbol number or -ve section id */
  25.     int bytes;                   /* 2 or 4 */
  26.     int relative;               /* TRUE or FALSE */
  27. };
  28.  
  29. struct Symbol {
  30.     long strpos;               /* string table position of name */
  31.     int type;                   /* symbol type - see flags below */
  32.     long value;                   /* address, or COMMON variable size */
  33. };
  34.  
  35. /*
  36.  * Section IDs - used in Reloc.symbol when negative, and in
  37.  * Symbol.type when positive.
  38.  */
  39. #define SECT_ABS 2               /* absolute value */
  40. #define SECT_TEXT 4               /* text section */
  41. #define SECT_DATA 6               /* data section */
  42. #define SECT_BSS 8               /* bss section */
  43. #define SECT_MASK 0xE               /* mask out any of the above */
  44.  
  45. /*
  46.  * Another flag used in Symbol.type.
  47.  */
  48. #define SYM_GLOBAL 1               /* it's a global symbol */
  49.  
  50. /*
  51.  * Bit more explanation of symbol types: SECT_xxx denotes a local
  52.  * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
  53.  * this module. Just SYM_GLOBAL, with zero value, denotes an
  54.  * external symbol referenced in this module. And just SYM_GLOBAL,
  55.  * but with a non-zero value, declares a C `common' variable, of
  56.  * size `value'.
  57.  */
  58.  
  59. struct Section {
  60.     struct SAA *data;
  61.     unsigned long len, size, nrelocs;
  62.     long index;
  63.     struct Reloc *head, **tail;
  64. };
  65.  
  66. static struct Section stext, sdata;
  67. static unsigned long bsslen;
  68. static long bssindex;
  69.  
  70. static struct SAA *syms;
  71. static unsigned long nsyms;
  72.  
  73. static struct RAA *bsym;
  74.  
  75. static struct SAA *strs;
  76. static unsigned long strslen;
  77.  
  78. static FILE *aoutfp;
  79. static efunc error;
  80.  
  81. static void aout_write(void);
  82. static void aout_write_relocs(struct Reloc *);
  83. static void aout_write_syms(void);
  84. static void aout_sect_write(struct Section *, unsigned char *, unsigned long);
  85. static void aout_pad_sections(void);
  86. static void aout_fixup_relocs(struct Section *);
  87.  
  88. static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef) {
  89.     aoutfp = fp;
  90.     error = errfunc;
  91.     (void) ldef;               /* placate optimisers */
  92.     stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head;
  93.     sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head;
  94.     stext.len = stext.size = sdata.len = sdata.size = bsslen = 0;
  95.     stext.nrelocs = sdata.nrelocs = 0;
  96.     stext.index = seg_alloc();
  97.     sdata.index = seg_alloc();
  98.     bssindex = seg_alloc();
  99.     syms = saa_init((long)sizeof(struct Symbol));
  100.     nsyms = 0;
  101.     bsym = raa_init();
  102.     strs = saa_init(1L);
  103.     strslen = 0;
  104. }
  105.  
  106. static void aout_cleanup(void) {
  107.     struct Reloc *r;
  108.  
  109.     aout_pad_sections();
  110.     aout_fixup_relocs(&stext);
  111.     aout_fixup_relocs(&sdata);
  112.     aout_write();
  113.     fclose (aoutfp);
  114.     saa_free (stext.data);
  115.     while (stext.head) {
  116.     r = stext.head;
  117.     stext.head = stext.head->next;
  118.     nasm_free (r);
  119.     }
  120.     saa_free (sdata.data);
  121.     while (sdata.head) {
  122.     r = sdata.head;
  123.     sdata.head = sdata.head->next;
  124.     nasm_free (r);
  125.     }
  126.     saa_free (syms);
  127.     raa_free (bsym);
  128.     saa_free (strs);
  129. }
  130.  
  131. static long aout_section_names (char *name, int pass, int *bits) {
  132.     /*
  133.      * Default to 32 bits.
  134.      */
  135.     if (!name)
  136.     *bits = 32;
  137.  
  138.     if (!name)
  139.     return stext.index;
  140.  
  141.     if (!strcmp(name, ".text"))
  142.     return stext.index;
  143.     else if (!strcmp(name, ".data"))
  144.     return sdata.index;
  145.     else if (!strcmp(name, ".bss"))
  146.     return bssindex;
  147.     else
  148.     return NO_SEG;
  149. }
  150.  
  151. static void aout_deflabel (char *name, long segment, long offset,
  152.                int is_global) {
  153.     int pos = strslen+4;
  154.     struct Symbol *sym;
  155.  
  156.     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  157.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  158.     return;
  159.     }
  160.  
  161.     saa_wbytes (strs, name, (long)(1+strlen(name)));
  162.     strslen += 1+strlen(name);
  163.  
  164.     sym = saa_wstruct (syms);
  165.  
  166.     sym->strpos = pos;
  167.     sym->type = is_global ? SYM_GLOBAL : 0;
  168.     if (segment == NO_SEG)
  169.     sym->type |= SECT_ABS;
  170.     else if (segment == stext.index)
  171.     sym->type |= SECT_TEXT;
  172.     else if (segment == sdata.index)
  173.     sym->type |= SECT_DATA;
  174.     else if (segment == bssindex)
  175.     sym->type |= SECT_BSS;
  176.     else
  177.     sym->type = SYM_GLOBAL;
  178.     if (is_global == 2)
  179.     sym->value = offset;
  180.     else
  181.     sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
  182.  
  183.     /*
  184.      * define the references from external-symbol segment numbers
  185.      * to these symbol records.
  186.      */
  187.     if (segment != NO_SEG && segment != stext.index &&
  188.     segment != sdata.index && segment != bssindex)
  189.     bsym = raa_write (bsym, segment, nsyms);
  190.  
  191.     nsyms++;
  192. }
  193.  
  194. static void aout_add_reloc (struct Section *sect, long segment,
  195.                 int relative, int bytes) {
  196.     struct Reloc *r;
  197.  
  198.     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
  199.     sect->tail = &r->next;
  200.     r->next = NULL;
  201.  
  202.     r->address = sect->len;
  203.     r->symbol = (segment == NO_SEG ? -SECT_ABS :
  204.          segment == stext.index ? -SECT_TEXT :
  205.          segment == sdata.index ? -SECT_DATA :
  206.          segment == bssindex ? -SECT_BSS :
  207.          raa_read(bsym, segment));
  208.     r->relative = relative;
  209.     r->bytes = bytes;
  210.  
  211.     sect->nrelocs++;
  212. }
  213.  
  214. static void aout_out (long segto, void *data, unsigned long type,
  215.               long segment, long wrt) {
  216.     struct Section *s;
  217.     long realbytes = type & OUT_SIZMASK;
  218.     unsigned char mydata[4], *p;
  219.  
  220.     if (wrt != NO_SEG) {
  221.     wrt = NO_SEG;               /* continue to do _something_ */
  222.     error (ERR_NONFATAL, "WRT not supported by a.out output format");
  223.     }
  224.  
  225.     type &= OUT_TYPMASK;
  226.  
  227.     /*
  228.      * handle absolute-assembly (structure definitions)
  229.      */
  230.     if (segto == NO_SEG) {
  231.     if (type != OUT_RESERVE)
  232.         error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
  233.            " space");
  234.     return;
  235.     }
  236.  
  237.     if (segto == stext.index)
  238.     s = &stext;
  239.     else if (segto == sdata.index)
  240.     s = &sdata;
  241.     else if (segto == bssindex)
  242.     s = NULL;
  243.     else {
  244.     error(ERR_WARNING, "attempt to assemble code in"
  245.           " segment %d: defaulting to `.text'", segto);
  246.     s = &stext;
  247.     }
  248.  
  249.     if (!s && type != OUT_RESERVE) {
  250.     error(ERR_WARNING, "attempt to initialise memory in the"
  251.           " BSS section: ignored");
  252.     if (type == OUT_REL2ADR)
  253.         realbytes = 2;
  254.     else if (type == OUT_REL4ADR)
  255.         realbytes = 4;
  256.     bsslen += realbytes;
  257.     return;
  258.     }
  259.  
  260.     if (type == OUT_RESERVE) {
  261.     if (s) {
  262.         error(ERR_WARNING, "uninitialised space declared in"
  263.           " %s section: zeroing",
  264.           (segto == stext.index ? "code" : "data"));
  265.         aout_sect_write (s, NULL, realbytes);
  266.     } else
  267.         bsslen += realbytes;
  268.     } else if (type == OUT_RAWDATA) {
  269.     if (segment != NO_SEG)
  270.         error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  271.     aout_sect_write (s, data, realbytes);
  272.     } else if (type == OUT_ADDRESS) {
  273.     if (segment != NO_SEG) {
  274.         if (segment % 2) {
  275.         error(ERR_NONFATAL, "a.out format does not support"
  276.               " segment base references");
  277.         } else
  278.         aout_add_reloc (s, segment, FALSE, realbytes);
  279.     }
  280.     p = mydata;
  281.     if (realbytes == 2)
  282.         WRITESHORT (p, *(long *)data);
  283.     else
  284.         WRITELONG (p, *(long *)data);
  285.     aout_sect_write (s, mydata, realbytes);
  286.     } else if (type == OUT_REL2ADR) {
  287.     if (segment == segto)
  288.         error(ERR_PANIC, "intra-segment OUT_REL2ADR");
  289.     if (segment != NO_SEG && segment % 2) {
  290.         error(ERR_NONFATAL, "a.out format does not support"
  291.           " segment base references");
  292.     } else
  293.         aout_add_reloc (s, segment, TRUE, 2);
  294.     p = mydata;
  295.     WRITESHORT (p, *(long*)data-(realbytes + s->len));
  296.     aout_sect_write (s, mydata, 2L);
  297.     } else if (type == OUT_REL4ADR) {
  298.     if (segment == segto)
  299.         error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  300.     if (segment != NO_SEG && segment % 2) {
  301.         error(ERR_NONFATAL, "a.out format does not support"
  302.           " segment base references");
  303.     } else
  304.         aout_add_reloc (s, segment, TRUE, 4);
  305.     p = mydata;
  306.     WRITELONG (p, *(long*)data-(realbytes + s->len));
  307.     aout_sect_write (s, mydata, 4L);
  308.     }
  309. }
  310.  
  311. static void aout_pad_sections(void) {
  312.     static unsigned char pad[] = { 0x90, 0x90, 0x90, 0x90 };
  313.     /*
  314.      * Pad each of the text and data sections with NOPs until their
  315.      * length is a multiple of four. (NOP == 0x90.) Also increase
  316.      * the length of the BSS section similarly.
  317.      */
  318.     aout_sect_write (&stext, pad, (-stext.len) & 3);
  319.     aout_sect_write (&sdata, pad, (-sdata.len) & 3);
  320.     bsslen = (bsslen + 3) & ~3;
  321. }
  322.  
  323. /*
  324.  * a.out files have the curious property that all references to
  325.  * things in the data or bss sections are done by addresses which
  326.  * are actually relative to the start of the _text_ section, in the
  327.  * _file_. (No relation to what happens after linking. No idea why
  328.  * this should be so. It's very strange.) So we have to go through
  329.  * the relocation table, _after_ the final size of each section is
  330.  * known, and fix up the relocations pointed to.
  331.  */
  332. static void aout_fixup_relocs(struct Section *sect) {
  333.     struct Reloc *r;
  334.  
  335.     saa_rewind (sect->data);
  336.     for (r = sect->head; r; r = r->next) {
  337.     unsigned char *p, *q, blk[4];
  338.     long l;
  339.  
  340.     saa_fread (sect->data, r->address, blk, (long)r->bytes);
  341.     p = q = blk;
  342.     l = *p++;
  343.     l += ((long)*p++) << 8;
  344.     if (r->bytes == 4) {
  345.         l += ((long)*p++) << 16;
  346.         l += ((long)*p++) << 24;
  347.     }
  348.     if (r->symbol == -SECT_DATA)
  349.         l += stext.len;
  350.     else if (r->symbol == -SECT_BSS)
  351.         l += stext.len + sdata.len;
  352.     if (r->bytes == 4)
  353.         WRITELONG(q, l);
  354.     else
  355.         WRITESHORT(q, l);
  356.     saa_fwrite (sect->data, r->address, blk, (long)r->bytes);
  357.     }
  358. }
  359.  
  360. static void aout_write(void) {
  361.     /*
  362.      * Emit the a.out header.
  363.      */
  364.     fwritelong (0x640107L, aoutfp);    /* OMAGIC, M_386, no flags */
  365.     fwritelong (stext.len, aoutfp);
  366.     fwritelong (sdata.len, aoutfp);
  367.     fwritelong (bsslen, aoutfp);
  368.     fwritelong (nsyms * 12, aoutfp);   /* length of symbol table */
  369.     fwritelong (0L, aoutfp);           /* object files have no entry point */
  370.     fwritelong (stext.nrelocs * 8, aoutfp);   /* size of text relocs */
  371.     fwritelong (sdata.nrelocs * 8, aoutfp);   /* size of data relocs */
  372.  
  373.     /*
  374.      * Write out the code section and the data section.
  375.      */
  376.     saa_fpwrite (stext.data, aoutfp);
  377.     saa_fpwrite (sdata.data, aoutfp);
  378.  
  379.     /*
  380.      * Write out the relocations.
  381.      */
  382.     aout_write_relocs (stext.head);
  383.     aout_write_relocs (sdata.head);
  384.  
  385.     /*
  386.      * Write the symbol table.
  387.      */
  388.     aout_write_syms ();
  389.  
  390.     /*
  391.      * And the string table.
  392.      */
  393.     fwritelong (strslen+4, aoutfp);    /* length includes length count */
  394.     saa_fpwrite (strs, aoutfp);
  395. }
  396.  
  397. static void aout_write_relocs (struct Reloc *r) {
  398.     while (r) {
  399.     unsigned long word2;
  400.  
  401.     fwritelong (r->address, aoutfp);
  402.  
  403.     if (r->symbol >= 0)
  404.         word2 = r->symbol | 0x8000000L;
  405.     else
  406.         word2 = -r->symbol;
  407.     if (r->relative)
  408.         word2 |= 0x1000000L;
  409.     word2 |= (r->bytes == 2 ? 0x2000000L : 0x4000000L);
  410.     fwritelong (word2, aoutfp);
  411.  
  412.     r = r->next;
  413.     }
  414. }
  415.  
  416. static void aout_write_syms (void) {
  417.     int i;
  418.  
  419.     saa_rewind (syms);
  420.     for (i=0; i<nsyms; i++) {
  421.     struct Symbol *sym = saa_rstruct(syms);
  422.     fwritelong (sym->strpos, aoutfp);
  423.     fwritelong ((long)sym->type, aoutfp);
  424.     /*
  425.      * Fix up the symbol value now we know the final section
  426.      * sizes.
  427.      */
  428.     if ((sym->type & SECT_MASK) == SECT_DATA)
  429.         sym->value += stext.len;
  430.     if ((sym->type & SECT_MASK) == SECT_BSS)
  431.         sym->value += stext.len + sdata.len;
  432.     fwritelong (sym->value, aoutfp);
  433.     }
  434. }
  435.  
  436. static void aout_sect_write (struct Section *sect,
  437.                  unsigned char *data, unsigned long len) {
  438.     saa_wbytes (sect->data, data, len);
  439.     sect->len += len;
  440. }
  441.  
  442. static long aout_segbase (long segment) {
  443.     return segment;
  444. }
  445.  
  446. static int aout_directive (char *directive, char *value, int pass) {
  447.     return 0;
  448. }
  449.  
  450. static void aout_filename (char *inname, char *outname, efunc error) {
  451.     standard_extension (inname, outname, ".o", error);
  452. }
  453.  
  454. struct ofmt of_aout = {
  455.     "GNU a.out (i386) object files (e.g. Linux)",
  456.     "aout",
  457.     aout_init,
  458.     aout_out,
  459.     aout_deflabel,
  460.     aout_section_names,
  461.     aout_segbase,
  462.     aout_directive,
  463.     aout_filename,
  464.     aout_cleanup
  465. };
  466.  
  467. #endif /* OF_AOUT */
  468.